package com.suray.wcs.service.plc;

import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.plc.entity.PlcDeviceDB;
import com.suray.basic.wcs.plc.enums.PlcDeviceType;
import com.suray.basic.wcs.plc.service.impl.PlcDeviceDBServiceImpl;
import com.suray.basic.wcs.utils.Coord;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.wcs.service.core.util.LockNodeManager;
import com.suray.wcs.service.enums.TaskType;
import com.suray.wcs.service.system.entity.ProgrammeDB;
import com.suray.wcs.service.system.entity.TaskDB;
import com.suray.wcs.service.system.service.impl.ProgrammeServiceImpl;
import com.suray.wcs.service.util.WcsUtil;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 自卸式提升机路径起点与终点处理
 */
public class LifterPathNode {

    private static ProgrammeServiceImpl programmeService = SpringContextHolder.getBean(ProgrammeServiceImpl.class);

    private static PlcDeviceDBServiceImpl plcDeviceDBService = SpringContextHolder.getBean(PlcDeviceDBServiceImpl.class);

    /**
     * 获取提升路径起点终点
     *
     * @param taskDB
     * @return List.get(0)为起点, List.get(1)为终点
     */
    public static List<Node> handleTask(TaskDB taskDB) {
        List<Node> pathStartAndEnd = new ArrayList<>();
        if (taskDB.getTaskType() == TaskType.TRANSFER) {
            String lifterPath = taskDB.getLifterPath();
            String[] lifterPathStr = lifterPath.split(";");
            pathStartAndEnd.add(Node.parseGrid(lifterPathStr[0]));
            pathStartAndEnd.add(Node.parseGrid(lifterPathStr[2]));
        } else if (taskDB.getTaskType() == TaskType.IN) {
            Node startNode = taskDB.selectStartNode();
            Node inPort = getProgrammePort(taskDB);
            pathStartAndEnd.add(inPort);
            pathStartAndEnd.add(startNode);
        } else if (taskDB.getTaskType() == TaskType.OUT) {
            Node endNode = taskDB.selectEndNode();
            Node outPort = getProgrammePort(taskDB);
            pathStartAndEnd.add(endNode);
            pathStartAndEnd.add(outPort);
        }
        return pathStartAndEnd;
    }

    /**
     * 执行提升机任务前锁定提升机接驳点
     *
     * @param taskDB
     */
    public static void taskBefore(TaskDB taskDB) {
        List<Node> nodes = handleTask(taskDB);
        Set<Coord> setList = getSetList(nodes);
        while (isLock(setList)) {
            WcsUtil.delay(1000);
        }
        LockNodeManager.lockedNodes(setList, taskDB);
    }

    /**
     * 提升机任务执行后解锁提升机接驳点
     *
     * @param taskDB
     */
    public static void taskAfter(TaskDB taskDB) {
        List<Node> nodes = handleTask(taskDB);
        LockNodeManager.unlockedNodes(getSetList(nodes), taskDB);
    }

    /**
     * 将coord转换为set<Coord>集合
     *
     * @param nodes
     * @return
     */
    private static Set<Coord> getSetList(List<Node> nodes) {
        HashSet<Coord> coordHashSet = new HashSet<>();
        for (int i = 0; i < nodes.size(); i++) {
            coordHashSet.add(nodes.get(i));
        }
        return coordHashSet;
    }

    private static boolean isLock(Set<Coord> coords) {
        for (Coord coord : coords) {
            if (LockNodeManager.checkNodesLocked(coord)) {
                LoggerUtil.info("等待节点" + coord + "被解锁", LifterPathNode.class);
                return true;
            }
        }
        return false;
    }

    private static Node getProgrammePort(TaskDB taskDB) {
        ProgrammeDB proNode = programmeService.selectByProgrammeId(Long.valueOf(taskDB.getTaskProgrammeGridId()));
        String programme = proNode.getProgramme();
        String[] split = programme.split("-");
        String deviceLocation = findDeviceLocation(split);
        Node node = Node.parseGrid(deviceLocation);
        node.setZ(proNode.getProgrammeFloor());
        return node;
    }

    private static String findDeviceLocation(String[] list) {
        for (String str : list) {
            if (str.equals("999")) {
                continue;
            }
            PlcDeviceDB plcDeviceDB = plcDeviceDBService.getPlcDevById(Integer.valueOf(str));
            if (plcDeviceDB.getDeviceType() == PlcDeviceType.AUTOMATIC_LIFTER.getTypeNum()) {
                return plcDeviceDB.getDeviceLocation();
            }
        }
        throw new RuntimeException("方案配置为空,请检查方案配置");
    }
}
